<template>
    <!-- <div class="testBBBB">
        <br>
    <button @click="testBtn">触发按钮</button>
    <br>
    <button @click="testBtn2">触发按钮2{{}}</button>
    <br>
    <button @click="testBtn3">触发按钮3{{resizeStore.isKeyboardStatus}}</button>
    <br>
    </div> -->
    <div class="msgListStyle" id="msgListId" @scroll="handleScroll" @touchmove="isBottom = false"
    :style="resizeStore.isKeyboardStatus ? `height: calc(100% - 40px - ${sendWindowHeight}px );`: `height: calc(100% - 91px - ${sendWindowHeight}px);`">
        <TalkItem :msgList="msgList"/>
        <div class="robotLoadingLottieStyle" ref="robotLoadingLottieRef" v-show="robotLoadingStatus" :style="`margin-top: -${34 + robotLoadingCurrentHeight}px;`"></div>
        <MsgListEmpty v-if="msgList.length == 0" ref="msgListEmptyRef"/>
        <svg t="1698211441027" class="toBottomIconStyle" :style="`bottom:${sendWindowHeight + 51 + 50}px`" @click="toBottomBtn" v-show="toBottomBtnShow" viewBox="0 0 1097 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4275" width="200" height="200"><path d="M516.226955 1.249085c68.9495 0 135.900464 13.49012 198.979263 40.095633 60.830446 25.731154 115.540376 62.579166 162.381068 109.544767 46.965601 46.965601 83.688705 101.550622 109.544767 162.381069 26.605514 62.953891 40.095633 129.904855 40.095633 198.979263 0 68.9495-13.49012 135.900464-40.095633 198.979263-25.731154 60.830446-62.579166 115.540376-109.544767 162.381069-46.965601 46.965601-101.550622 83.688705-162.381068 109.544767-62.953891 26.605514-129.904855 40.095633-198.979263 40.095633-68.9495 0-135.900464-13.49012-198.979264-40.095633-60.830446-25.731154-115.540376-62.579166-162.381068-109.544767-46.965601-46.965601-83.688705-101.550622-109.544767-162.381069-26.605514-62.953891-40.095633-129.904855-40.095633-198.979263 0-68.9495 13.49012-135.900464 40.095633-198.979263 25.731154-60.830446 62.579166-115.540376 109.544767-162.381069 46.965601-46.965601 101.550622-83.688705 162.381068-109.544767C380.326491 14.739205 447.277455 1.249085 516.226955 1.249085z m-1.124177 596.812881L326.116196 409.075384c-5.620883-5.620883-13.115394-8.743596-20.984631-8.743596-7.869236 0-15.363747 3.122713-20.98463 8.743596s-8.743596 13.115394-8.743596 20.984631c0 7.869236 3.122713 15.363747 8.743596 20.98463l209.846304 209.846304c11.616492 11.616492 30.352769 11.616492 41.969261 0l209.846304-209.846304c5.620883-5.620883 8.743596-13.115394 8.743596-20.98463 0-7.869236-3.122713-15.363747-8.743596-20.984631s-12.990485-8.743596-20.984631-8.743596c-7.869236 0-15.363747 3.122713-20.98463 8.743596L515.102778 598.061966z m0 0" p-id="4276" 
            fill="#8a8a8a"></path></svg>
    </div>
    <div class="sendWindowStyle" :style="expandFullScreenStatus ? 'bottom: 91px;':''">
        <svg t="1698145620282" class="fullScreenIconStyle" v-show="expandFullScreenStatus"
        @click="expandFullScreenStatus = !expandFullScreenStatus" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2868" id="mx_n_1698145620284" width="200" height="200"><path d="M931.81 889.09L739.02 696.3H907.6c16.57 0 30-13.43 30-30s-13.43-30-30-30h-241c-16.57 0-30 13.43-30 30v241c0 16.57 13.43 30 30 30s30-13.43 30-30V738.73l192.79 192.79a29.893 29.893 0 0 0 21.21 8.79c7.68 0 15.36-2.93 21.21-8.79 11.71-11.72 11.71-30.71 0-42.43zM357.22 85.93c-16.57 0-30 13.43-30 30V284.5L134.44 91.71c-11.72-11.72-30.71-11.72-42.43 0-11.72 11.72-11.72 30.71 0 42.43L284.8 326.93H116.22c-16.57 0-30 13.43-30 30s13.43 30 30 30h241c16.57 0 30-13.43 30-30v-241c0-16.57-13.43-30-30-30z" fill="#000000" p-id="2869"></path></svg>
        <svg t="1698145839944" class="fullScreenIconStyle" v-show="!expandFullScreenStatus" v-if="currentLineNum > 2"
        @click="expandFullScreenStatus = !expandFullScreenStatus" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3443" width="200" height="200"><path d="M377.93 645.39c-11.72-11.72-30.71-11.72-42.43 0L143.22 837.67V669.51c0-16.57-13.43-30-30-30s-30 13.43-30 30v241c0 16.57 13.43 30 30 30h241c16.57 0 30-13.43 30-30s-13.43-30-30-30H185.23l192.7-192.7c11.71-11.71 11.71-30.7 0-42.42zM940.59 112.87c0.04-7.73-2.89-15.47-8.78-21.37-7.13-7.13-16.96-9.91-26.2-8.36H669.59c-16.57 0-30 13.43-30 30s13.43 30 30 30h168.15L645.89 334.99c-11.72 11.72-11.72 30.71 0 42.43a29.893 29.893 0 0 0 21.21 8.79c7.68 0 15.36-2.93 21.21-8.79L880.6 185.14v169c0 16.57 13.43 30 30 30s30-13.43 30-30v-241c0-0.09-0.01-0.18-0.01-0.27z" fill="#000000" p-id="3444"></path></svg>
        <span class="sendBtnStyle" @click="sendBtn" :style="sendContent ? (sendBtnPressStatus ? 'background-color: rgb(28, 139, 65);' : 'background-color: rgb(34, 167, 78);' ) : ''"
        @touchstart="sendBtnPressStatus = true" @touchend="sendBtnPressStatus = false" @touchcancel="sendBtnPressStatus = false">发送</span>
        <textarea class="textareaStyle" v-model="sendContent" :disabled="inputDisableStatus"
        @keydown="handleKeyDown"
        id="textareaId"
        :style="expandFullScreenStatus? 'height: calc(100vh - 117px);':`${textCurrentHeightStyle} + -webkit-scrollbar { display: none; }`"></textarea>
        <textarea class="textareaStyle2" v-model="sendContent"
        id="textareaId2"
        :style="`${textCurrentHeightStyle2}`"></textarea>
        <!-- height: calc(40px - 1rem); -->
        <!-- 24px为一行，第4行就是112 -->
        <!-- 112 -->
        <!-- 88 -->
        <!-- 64 -->
        <!-- 40 -->
        <!--  -->
    </div>
</template>
<script setup>
import { v4 as uuidv4 } from 'uuid';
import lottie from "lottie-web";
import {getAuthSession,getAccountsCheck,getModels,getConversationList,getConversationById,conversationTalk,
    editConversationById,inferConversationTitle} from '@/api/chat'
import { onMounted, ref ,getCurrentInstance, reactive, nextTick,onBeforeUnmount, watch} from 'vue'
import TalkItem from './talkItem.vue'
import MsgListEmpty from './msgListEmpty.vue'
import { useResizeStore } from '@/store/modules/resize'
import useTalkStore from '@/store/modules/talk'
defineEmits(['doLoading'])

let resizeStore = useResizeStore()
const { proxy } = getCurrentInstance()

const testBtn =()=>{
}
const testBtn2 = ()=>{
}
const testBtn3 = ()=>{
}

let robotLoadingLot = ref()
let robotLoadingJson = new URL('@/assets/lotties/robotLoading.json', import.meta.url).href
let robotLoadingStatus = ref()
let robotLoadingCurrentHeight = ref()
onMounted(()=>{
    robotLoadingLot.value = lottie.loadAnimation({
        container: proxy.$refs[`robotLoadingLottieRef`],
        renderer: "svg",
        loop: true,
        autoplay: false,
        path: robotLoadingJson
    })
    robotLoadingLot.value.play()
})
onBeforeUnmount(()=>{
    if(robotLoadingLot.value != null){
        robotLoadingLot.value.destroy()
        robotLoadingLot.value = null
    }
})


let expandFullScreenStatus = ref(false)
let sendWindowHeight = ref()
let currentLineNum = ref(1) //默认一行
let textCurrentHeightStyle = ref('height: calc(40px - 1rem);')
let sendContent = ref('')
onMounted(()=>{
    sendWindowHeight.value = document.getElementById('textareaId').clientHeight + 16 * .4 + 4
})
let textCurrentHeightStyle2 = ref('height: calc(40px - 1rem);')
// 监视内容的行数
function countLines(val) {
    judgeIsBottom()
    // 1rem 等于根元素字体大小，通常是 16px。1rem = 16px
    // const textarea = document.getElementById('textareaId')
    // const totalLines = ( textarea.scrollHeight - 16 ) / 24
    const totalLines = ( val - 16 ) / 24
    currentLineNum.value = totalLines;
    let pxNum = 40 + (24 * ((totalLines > 6 ? 6 : totalLines ) - 1))
    textCurrentHeightStyle.value = `height: calc(${pxNum}px - 1rem );`
    sendWindowHeight.value = pxNum + 16 * .4 + 4
    setTimeout(() => {
        if(isBottom.value){
            toBottomBtn()
        }
    }, 10);
}
let handleKeyDownTimer = ref(null)
const handleKeyDown = (event)=>{    //handleKeyDown方法要比countLines先
    if(event.key == 'Backspace' || event.key == 'Delete'){
        textCurrentHeightStyle2.value = `height: calc(${40}px - 1rem );`
    }
    if(handleKeyDownTimer.value == null){
        handleKeyDownTimer.value = setTimeout(() => {
            countLines(document.getElementById('textareaId2').scrollHeight)
            clearTimeout(handleKeyDownTimer.value)
            handleKeyDownTimer.value = null
        },10);
    }
}
const initSendWindowStyle = ()=>{
    expandFullScreenStatus.value = false
    textCurrentHeightStyle.value = `height: calc(${40}px - 1rem );`
    sendContent.value = ''
    sendWindowHeight.value = 40 + 16 * .4 + 4
    currentLineNum.value = 1
}
watch(() => resizeStore.isKeyboardStatus, (newVal, oldVal) => {
    // console.log(newVal,isBottom.value);
    if(isBottom.value){
        setTimeout(() => {
            toBottomBtn()
        }, 10);
    }
});

let sendBtnPressStatus = ref(false)
let talkStore = useTalkStore()
let inputDisableStatus = ref(false)
const sendBtn = async()=>{
    if(sendContent.value != '' && sendContent.value != null){
        userCurrentMsgId.value = uuidv4()
        if(localStorage.getItem('conversation_id') != null){
            try {
                msgList.value.push(userTalkModel())
                msgList.value.push(robotTalkModel())
                setTimeout(() => {
                    initSendWindowStyle()
                    toBottomBtn()
                    robotLoadingStatus.value = true
                    robotLoadingCurrentHeight.value = document.getElementById('msgListId').scrollTop;
                    inputDisableStatus.value = true
                }, 10);
                const talkRes = await conversationTalk({
                    conversation_id: localStorage.getItem('conversation_id'),
                    message_id: userCurrentMsgId.value,
                    model: "text-davinci-002-render-sha",
                    parent_message_id: localStorage.getItem('parent_message_id'),
                    prompt: userContentFormatSend(sendContent.value),
                    timezone_offset_min: 240
                })
                robotLoadingStatus.value = false
                await dealWithReply(talkRes,false)
            } catch (error) {
                console.error('获取数据时出错:', error);
            }
        }else{
            try {
                msgList.value = []
                msgList.value.push(userTalkModel())
                msgList.value.push(robotTalkModel())
                if(proxy.$refs['msgListEmptyRef'].noMsgLot.value != null){
                    proxy.$refs['msgListEmptyRef'].noMsgLot.value.destroy()
                    proxy.$refs['msgListEmptyRef'].noMsgLot.value = null
                }
                setTimeout(() => {
                    initSendWindowStyle()
                    toBottomBtn()
                    robotLoadingStatus.value = true
                    robotLoadingCurrentHeight.value = document.getElementById('msgListId').scrollTop;
                    inputDisableStatus.value = true
                }, 10);
                const firstTalkRes = await conversationTalk({
                    prompt:userContentFormatSend(sendContent.value),
                    message_id:userCurrentMsgId.value,
                    parent_message_id:uuidv4(),
                    model:'text-davinci-002-render-sha',
                    timezone_offset_min:240
                })
                robotLoadingStatus.value = false
                await dealWithReply(firstTalkRes,true)
                const conversationList = await getConversationList({
                    offset : 0,
                    limit : 1
                });
                localStorage.setItem('conversation_id',conversationList.items[0].id)

                if(talkStore.talkTitleStatus){
                    await editConversationById({
                        id:conversationList.items[0].id,
                        data:{title:localStorage.getItem('talkName')}
                    })
                }else{
                    let data = await inferConversationTitle({
                        id : conversationList.items[0].id,
                        data :{
                            message_id:userCurrentMsgId.value,
                            model:'text-davinci-002-render-sha'
                        }
                    })
                    localStorage.setItem('talkName',data.title)
                    talkStore.setTalkTitle(data.title)
                    talkStore.setTalkTitleStatus(true)
                }
            } catch (error) {
                console.error('获取数据时出错:', error);
            }
        }
    }
}
let userCurrentMsgId = ref()
const userContentFormatShow = (val)=>{
    return val.replace(/\n/g, '<br>').replace(/ /g, '&ensp;');
}
const userContentFormatSend = (val)=>{
    return val.replace(/\n/g, '\\n');
}
const userTalkModel = ()=>{
    return{
        message:{
            id:userCurrentMsgId.value,
            author:{
                role:'user'
            },
            content:{
                parts:[`${userContentFormatShow(sendContent.value)}`]
            }
        }
    }
}
const robotTalkModel = ()=>{
    return{
        message:{
            id:'',
            author:{
                role:'assistant'
            },
            content:{
                parts:[``]
            }
        }
    }
}
const dealWithReply = (data,ifFirst)=>{
    return new Promise((resolve, reject) => {
        let arr = data.split('\n')
        let arr2 = []
        arr.splice(-4,4)//有一个done得去掉，不然JSON.parse报错
        for(let i=0;i<arr.length;i++){
            if('data'.indexOf(arr[i])){
                arr2.push(JSON.parse(arr[i].slice(5)))
                
            }
        }
        console.log('arr2=>',arr2);
        if(ifFirst){
            arr2[2].message.content.parts[0] = formatContent(arr2[2].message.content.parts[0])
            msgList.value[msgList.value.length - 1] = arr2[2]
            arr2.splice(0,3)
        }else{
            msgList.value[msgList.value.length - 1] = arr2[0]
        }
        
        judgeIsBottom()
        if(!isBottom.value){//如果当前不是最底部，可以告诉用户信息来了
            newInfoStatus.value = true
            toBottomBtnShow.value = true
        }

        currentReplyContent.value = arr2
        localStorage.setItem('parent_message_id',arr2[arr2.length-1].message.id)

        replyStatus = true
        replyTimer.value = setInterval(() => {
            replyFun()
        }, 10);
        resolve();
    });
}

let replyIndex = 0
let currentReplyContent = ref([])
let replyTimer = ref()
const replyFun = ()=>{
    if(replyIndex < currentReplyContent.value.length){
        msgList.value[msgList.value.length - 1].message.content.parts[0] = formatContent(currentReplyContent.value[replyIndex].message.content.parts[0])
        replyIndex++
        if(isBottom.value){
            toBottomBtn()
        }else{
            newInfoStatus.value = true
            toBottomBtnShow.value = true
        }
    }else{
        if(!isBottom.value){
            newInfoStatus.value = true
            toBottomBtnShow.value = true
        }
        clearInterval(replyTimer.value)
        replyTimer.value = null
        replyIndex = 0
        replyStatus = false
        inputDisableStatus.value = false
    }
}

let msgList = ref([])
const formatContent = (text)=>{
    if (/```html/.test(text) || /```javascript/.test(text) || /```php/.test(text) || /```vue/.test(text)) { //如果有html标签的，需要转义，因为v-html需要防止xss攻击
        text = text.replace(/</g, '&lt;').replace(/>/g, '&gt;');
    }

    // 替换双星号为加粗
    text = text.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
    // 替换换行符为 <br>
    text = text.replace(/\n/g, '<br>');

    // // 包裹代码块
    // text = text.replace(/```(.*?)```/g, '<div class="customCode">$1</div>');

    // //如果有单个的```也要换
    // if(/```/.test(text)){
    //     text = text.replace(/```/g, '<div class="customCode">') + '</div>';
    // }

    // 替换 ``` 包裹的代码块内容
    text = text.replace(/```(.*?)```/g, (match, group) => {
        const formattedCode = group.replace(/ /g, '&ensp;');
        return `<div class="customCode">${formattedCode}</div>`;
    });

    // 如果有单个的 ``` 也要处理
    if (/```/.test(text)) {
        text = text.replace(/```([\s\S]*)/, (match, group) => {
            const formattedCode = group.replace(/ /g, '&ensp;');
            return `<div class="customCode">${formattedCode}</div>`;
        });
    }
    return text
}
onMounted(()=>{
    if(localStorage.getItem('conversation_id') != null){
        proxy.$emit('doLoading',true)
        getConversationById(localStorage.getItem('conversation_id')).then(res=>{
            fromGptMappingToArrayList(res.mapping)
        }).catch(()=>{
            proxy.$emit('doLoading',false)
            localStorage.clear()
            talkStore.setTalkTitle(null)
        })
    }
})
const fromGptMappingToArrayList = (data)=>{
    let nextKey = null
    let arrayList = []
    for(let key in data){
        if(data[key].parent == null){
            arrayList.push(data[key])
            // nextKey = data[nextKey]['children'][0]  //children[0]=>会有隐患
            nextKey = data[key]['children'][data[key]['children'].length -1]
            break;
        }
    }
    for(;true;){
        if(data[nextKey]['children'].length != 0){
            if(data[nextKey].message != null && data[nextKey].message.author.role == 'assistant'){
                data[nextKey].message.content.parts[0] = formatContent(data[nextKey].message.content.parts[0])
            }
            arrayList.push(data[nextKey])
            // nextKey = data[nextKey]['children'][0]
            nextKey = data[nextKey]['children'][data[nextKey]['children'].length -1]
        }else{
            if(data[nextKey].message != null && data[nextKey].message.author.role == 'assistant'){
                data[nextKey].message.content.parts[0] = formatContent(data[nextKey].message.content.parts[0])
            }
            arrayList.push(data[nextKey])
            localStorage.setItem('parent_message_id',data[nextKey].message.id)
            break;
        }
    }
    msgList.value = arrayList
    proxy.$emit('doLoading',false)
    setTimeout(() => {
        toBottomBtn()
    }, 10);
    // console.log(toRaw(msgList.value),'@#@#');
}

let newInfoStatus = ref(false)
let isBottom = ref(false)
const judgeIsBottom = ()=>{
    const msgListDiv = document.getElementById('msgListId')
    const scrollHeight = msgListDiv.scrollHeight;
    const currentScrollTop = msgListDiv.scrollTop;
    const clientHeight = msgListDiv.clientHeight;

    //只要一开始在最底部,那么整个过程就是在最底部完成，因为速度太快了!
    isBottom.value = Boolean(Math.abs(scrollHeight - currentScrollTop - clientHeight) < 1)
    //👆这个需要改，体验不好，2023/10/31提出来（已经在touchmove上改了isBottom.value的值）

    
    // if(scrollHeight - currentScrollTop === clientHeight){   //如果在最底部
    //     console.log('是最底部');
    //     toBottomBtn()
    // }else{
    //     console.log('不是最底部');
    //     newInfoStatus.value = true
    //     toBottomBtnShow.value = true
    // }
}
const toBottomBtn = ()=>{
    document.getElementById('msgListId').scrollTop = document.getElementById('msgListId').scrollHeight
    toBottomBtnShow.value = false
    newInfoStatus.value = false
    isBottom.value = true
}
let toBottomBtnShow = ref(false)
// 初始化滚动位置
let prevScrollTop = 0;
let replyStatus = false
const handleScroll = () => {
    if(!replyStatus){
        const msgListDiv = document.getElementById('msgListId')
        const scrollHeight = msgListDiv.scrollHeight;
        const currentScrollTop = msgListDiv.scrollTop;
        robotLoadingCurrentHeight.value = msgListDiv.scrollTop;
        const clientHeight = msgListDiv.clientHeight;
        if(Math.abs(scrollHeight - currentScrollTop - clientHeight) < 1){
            isBottom.value = true
            toBottomBtnShow.value = false
            newInfoStatus.value = false
        }else if(!newInfoStatus.value){
            toBottomBtnShow.value = currentScrollTop > prevScrollTop
        }else{
            toBottomBtnShow.value = true
        }
        prevScrollTop = currentScrollTop
    }
}
defineExpose({//父组件可以直接使用
    msgList,
})
</script>
<style scoped lang="scss">
.testBBBB{
    position: absolute;
    left: 0;
    // right: 0;
    bottom: 70%;
    z-index: 99;
    color: white;
    background-color: rgba(66, 66, 66,.2);
}
.msgListStyle{
    background-color: rgb(240, 240, 240);
    background-color: white;
    overflow-y: auto;
    overflow-x: hidden;
    word-break:break-all;
    // height: calc(100% - 91px);//40+50+1的边
    .robotLoadingLottieStyle{
        width: 10rem;
        height: 10rem;
        position: absolute;
        transform: translateY(-50%);
        margin-left: 1rem;
        margin-top: -34px;
    }
    .toBottomIconStyle{
        position: absolute;
        height: 1.9rem;
        width: 1.9rem;
        right: .5rem;
    }
}
.msgListStyle::-webkit-scrollbar {
  display: none; /* Webkit (Safari, Chrome) */
}
.sendWindowStyle{
    padding-top: .4rem;
    padding-left: .6rem;
    width: calc(100% - .6rem);
    position: absolute;
    border: 0px;
    // box-shadow: 0px 0px 8px -5px rgb(161, 161, 161);
    background-color: rgb(250, 250, 250);
    .fullScreenIconStyle{
        right: 1rem;
        position: absolute;
        padding: .1rem;
        height: 1.2rem;
        width: 1.2rem;
        border-radius: 10%;
        background-color: #e7e7e7;
    }
    .sendBtnStyle{
        right: .5rem;
        position: absolute;
        font-size: 1rem;
        padding: .5rem;
        padding-right: .9rem;
        padding-left: .9rem;
        background-color: rgba(34, 167, 78,.6);
        border-radius: 4px;
        color: white;
        bottom: .3rem;
    }
    .textareaStyle2{
        top: -200px;
        left: 10px;
        position: absolute;
        opacity: 0;
        z-index: -99;

        padding-left: .8rem;
        padding-right: 1.3rem;
        padding-top: .5rem;
        padding-bottom: .5rem;
        width: calc((100% - .6rem) * .78 - 1.3rem - .8rem);
        letter-spacing: .5px;
        line-height: 1.5rem;
        font-size: 1.1rem;
        border: none;
        outline: none;
        resize:none;
        word-break: break-all;
        user-select:text;
        border-radius: 5px;
    }
    .textareaStyle{
        padding-left: .8rem;
        padding-right: 1.3rem;
        padding-top: .5rem;
        padding-bottom: .5rem;
        width: calc(78% - 1.3rem - .8rem);
        letter-spacing: .5px;
        line-height: 1.5rem;
        font-size: 1.1rem;
        border: none;
        outline: none;
        resize:none;
        word-break: break-all;
        user-select:text;
        border-radius: 5px;
    
        // height: calc(100vh - 117px);
        // transition: height .2s ease-in-out;
    }
}
// :v-deep(.customCode) {
//     margin-left: 10px;
//     margin-right: 10px;
//     background-color: #f0f0f0;
//     padding: 8px;
//     font-family: monospace;
// }
::v-deep .customCode {
    margin-left: 10px;
    margin-right: 10px;
    background-color: #f0f0f0;
    padding: 8px;
    font-family: monospace;
    overflow-x: scroll;
    width: calc(100% - 36px);
    position: relative;
    white-space: nowrap;
}
</style>